#include <LitStdAfx.h>
#include "LitString.h"
#include "LitExceptions.h"


LIT_API Lit::String operator + ( const char * str, const Lit::String &str2 ){ return Lit::String(str) + str2; }
LIT_API std::string operator + ( const std::string& str, const Lit::String &str2 ){ return str + str2.str(); }
LIT_API std::ostream& operator<<( std::ostream& strm, const Lit::String &str );

namespace Lit
{
	String::String( const String &rk ) : d( rk.d ){}
	String::String( const char * str ) : d( std::string( str ) ){}
	String::String( ){}
	bool String::endsWith( const Lit::String &str ) const
	{
		if( str.length() > length() ) return false;
		return ( d.substr( length()-str.length(), str.length() ) == str.str() );
	}
	void String::trim( ){
		Ogre::StringUtil::trim( d );
	}
	char &String::at( size_t i ) { return d.at( i ); }
	char& String::operator[]( size_t i ){ return d.at(i); }
	char String::at( size_t i ) const{ return d.at(i); }
		
	std::string* String::operator->(){ return &d; }
	const std::string* String::operator->() const{ return &d; }

	std::string& String::operator*(){ return d; }
	const std::string& String::operator*() const{ return d; }
		
	size_t String::replaceBy( const String& what, const String &to ) 
	{
		size_t npos = 0;
		size_t cnt = 0;
		while( (npos=d.find( what.str())) != std::string::npos )
		{
			d = d.replace( npos, what.length(), to.str() );
			cnt ++;
		}
		return cnt;
	}
	std::vector<Lit::String> String::tokenise( const std::string &delims, const std::string &double_delims ) const{
		Ogre::StringVector ret = Ogre::StringUtil::tokenise( d, delims, double_delims );
		std::vector<Lit::String> ret2;
		for( auto i=ret.begin(); i!=ret.end(); i++ ) ret2.push_back( String(*i) );
		return ret2;
	}
	void String::replaceAll( const std::string &what, const std::string &byWhat )
	{
		d = Ogre::StringUtil::replaceAll( d, what, byWhat );
	}
	void String::replace( iterator it, const String & str ){ d.erase(it); d.insert(it, str.begin(), str.end()); }
	void String::erase( iterator it ){ d.erase( it ); }
	bool String::empty() const{return d.empty();}
	size_t String::length() const{ return d.length(); }
	size_t String::size() const{ return d.length(); }
	size_t String::count() const{ return d.length(); }
	size_t String::capacity() const{ return d.capacity(); }
	size_t String::find( char c ) const{ return d.find( c ); }
	String String::substr( size_t pos, size_t count ) const{ return d.substr( pos, count ); }


	String::iterator String::find( char c ){ return (d.begin() + d.find( c )); }
	String::iterator String::begin(){ return d.begin(); }
	String::iterator String::end(){ return d.end(); }
	String::const_iterator String::begin() const{ return d.cbegin(); }
	String::const_iterator String::end() const{ return d.cend(); }
		
	bool String::operator<( Lit::String rk ) { return length() < rk.length(); }
	bool String::operator>( Lit::String rk ) { return length() > rk.length(); }
	bool String::operator==( const Lit::String &rk ) const{ return (rk.str() == d); }
	bool String::operator==( const std::string &rk ) const{ return (rk == d); }
	bool String::operator==( const char * str ) const{ return (d == std::string( str )); }

	String& String::operator += ( const char* rk ){ d += std::string(rk);  return *this;}
	String& String::operator += ( const String &rk ){ d += rk.d;  return *this;}

	String String::operator + ( const char* rk ) const{ return String(d + std::string(rk)); }
	String String::operator + ( const String &rk ) const{ return String(d + rk.d); }

	String& String::operator = ( const char* rk ){ d = std::string(rk);  return *this;}
	String& String::operator = ( const String &rk ){ d = rk.d;  return *this;}
		
	String& String::operator () ( const char* rk ){ d += std::string(rk);  return *this;}
		
	String& String::operator << ( const char* rk ){ d += std::string(rk);  return *this;}

	std::vector<Lit::String> String::explode( const String &delimiter ) const
	{
		std::vector<String> arr;
		size_t strleng = d.length();
		size_t delleng = delimiter.length();
		if (delleng==0)
			return arr;//no change
		if( d.find( delimiter.cstr() ) == std::string::npos ){ arr.push_back( d ); return arr; }
		size_t i=0; 
		int k=0;
		while( i<strleng )
		{
			size_t j=0;
			while (i+j<strleng && j<delleng && d[i+j]==delimiter.at(j)) j++;
			if (j==delleng)//found delimiter
			{
				arr.push_back(  d.substr(k, i-k) );
				i+=delleng;
				k=i;
			}
			else
			{
				i++;
			}
		}
		arr.push_back(  d.substr(k, i-k) );
		return arr;
	}

	std::string String::str() const{ return d; }
	const char* String::cstr() const{ return d.c_str(); }
		
	String::operator std::string	(void) const{ return str(); }
	String::operator char const *	(void) const{ return d.c_str(); }
};
namespace Lit
{
	Tokenizer::Tokenizer( ){}
	Tokenizer::Tokenizer( const std::string &str ){mStr=str;Ogre::StringUtil::trim( mStr );}
	Tokenizer::Tokenizer( const Tokenizer& rk ) : mStr(rk.mStr){}
	Tokenizer::~Tokenizer(){}

	std::string Tokenizer::arg( size_t id ) const{
		if( mStr.empty() ) return mStr;
		Ogre::StringVector vec = Ogre::StringUtil::tokenise( mStr, " " );
		if( id > vec.size()-1 )
			throw std::range_error("cannot extract argument #"+Ogre::StringConverter::toString(id));
		return vec[id];
	}

	bool Tokenizer::isValid( size_t requ_min_args ) const
	{
		if( mStr.empty() ) return false;
		size_t func_args = Ogre::StringUtil::tokenise( mStr, " " ).size();
		if( func_args >= requ_min_args )
			return true;
		return false;
	}
	std::string Tokenizer::str() const{
		return mStr;
	}

	Tokenizer Tokenizer::eat( size_t num )
	{
		Ogre::StringVector vec = Ogre::StringUtil::tokenise( mStr, " " );
		if( vec.empty() ) return *this;
		std::string str;
		for( auto i=vec.begin()+num; i!=vec.end(); i++ )
			str += (*i) + " ";
		return Tokenizer(str);
	}
	bool Tokenizer::hasNext() const
	{
		return !mStr.empty();
	}
	StringList::StringList( int default_ ) : mDefault(default_){}
	StringList::StringList( const std::string &def_str ) : mDefault(0), mDefaultStr(def_str){}
	StringList::StringList( const StringList & rk ) : mDefault( rk.mDefault ), mDefaultStr(rk.mDefaultStr), mStrings( rk.mStrings ){}
	StringList::StringList( int def_, const StringList & rk ) : mDefault(def_), mStrings( rk.mStrings ){}
	StringList::StringList( const std::string& def_, const StringList & rk ) : mDefaultStr(def_), mStrings( rk.mStrings ){}
	StringList::~StringList(){ clear(); }

	bool StringList::empty() const{ return mStrings.empty(); }
	size_t StringList::count() const{ return mStrings.size(); }
	
	String& StringList::at( size_t id ){
		if( id >= mStrings.size() )
			throw Lit::RuntimeError(Lit::EXC_ITEM_MISSING, "Id " + String(id) + " out of bounds [0,"+String(mStrings.size())+"] !", EXC_LOC);
		return mStrings[id];
	}
	const String& StringList::at( size_t id ) const{
		if( id >= mStrings.size() )
			throw Lit::RuntimeError(Lit::EXC_ITEM_MISSING, "Id " + String(id) + " out of bounds [0,"+String(mStrings.size())+"] !", EXC_LOC);
		return mStrings.at(id);
	}
	void StringList::setDefaultString( const std::string& default_ ){
		size_t id = 0;
		for( const_itor i=mStrings.begin(); i!=mStrings.end(); i++ )
		{
			if( (*i) == default_ ){
				mDefault = id;
				return;
			}
			id ++;
		}
		
	}
	bool StringList::has( const String &str ) const
	{
		for( const_itor i=mStrings.begin(); i!=mStrings.end(); i++ )
			if( (*i) == str ) return true;
		return false;
	}

	size_t StringList::findId( const String & str ) const{
		for( size_t i=0; i<mStrings.size(); i++ )
			if( mStrings.at(i) == str ) return i;
		return std::string::npos;
	}
		
	String StringList::selected() const{
		return mStrings.size() > mDefault ? mStrings.at(mDefault) : "" ;
	}
	StringList::itor StringList::find( const String &str ){
		for( itor i=mStrings.begin(); i!=mStrings.end(); i++ )
			if( (*i) == str.str() ) return i;
		return mStrings.end();
	}
	StringList::const_itor StringList::find( const String &str ) const{
		for( const_itor i=mStrings.begin(); i!=mStrings.end(); i++ )
			if( (*i) == str.str() ) return i;
		return mStrings.end();
	}
	StringList::itor StringList::begin(){ return mStrings.begin(); }
	StringList::itor StringList::end() { return mStrings.end(); }
	StringList::const_itor StringList::begin() const{ return mStrings.begin(); }
	StringList::const_itor StringList::end() const{ return mStrings.end(); }

	void StringList::clear(){ mStrings.clear(); }
	StringList& StringList::push( const String & str )
	{
		if( str == mDefaultStr )
		{
			mDefault = mStrings.size();
			mDefaultStr = "";
		}
		mStrings.push_back( str.str() );
		return *this;
	}
	String StringList::pop(){
		std::string str = mStrings.back().str();
		mStrings.pop_back();
		return str;
	}
		
	void StringList::setDefault( const size_t default_ ){ mDefault = default_; }
	size_t StringList::defaultString() const{ return mDefault; }

	StringList& StringList::operator()( const String &str ){ return push( str ); }
	StringList& StringList::operator<<( const String &str ){ return push( str ); }
		
	String StringList::str( const String &delim ) const{ 
		String s(String(mDefault)+delim);
		for( auto i=mStrings.begin(); i!=mStrings.end(); i++ )
		{
			s += String((*i) + delim);
		}
		return s;
	}
	StringList StringList::fromString( const String& str, const String& delim )
	{
		std::vector<String> v = str.explode(delim);
		StringList ret;
		if( v.empty() ) return StringList();
		if( v.size() == 1 ) return StringList().push("0").push(v.at(0));
		ret.setDefault( v.at(0).to<int>() );
		for( auto i=(v.begin()+1); i!=v.end(); i++ )
		{
			if( !(*i).empty() )
				ret<<(*i);
		}
		return ret;
	}
};
